package gbench.sandbox.matlib;
import org.junit.jupiter.api.Test;

import java.util.stream.Stream;

import gbench.common.fs.XlsFile.DataMatrix;
import gbench.common.matlib.MatlibCanvas;
import gbench.common.matlib.MatlibCanvas.NVec;
import gbench.common.matlib.MatlibCanvas.Range;
import gbench.common.matlib.MatlibCanvas.Seq;
import gbench.common.matlib.MatlibCanvas.XVec;
import gbench.common.matlib.img.ImageOps;
import gbench.common.tree.LittleTree;
import gbench.common.tree.LittleTree.KVPair;

import static java.lang.Math.PI;
import static gbench.common.matlib.MatlibCanvas.Range.P2;
import static gbench.common.matlib.MatlibCanvas.Range.rG;
import static gbench.common.matlib.MatlibCanvas.Range.rg;
import static gbench.common.tree.LittleTree.compose_f;
import static gbench.common.tree.LittleTree.IRecord.aaclc;
import static gbench.common.tree.LittleTree.IRecord.llclc;
import static gbench.common.tree.LittleTree.IRecord.ssclc;
import static gbench.common.tree.LittleTree.IRecord.A2REC;
import static gbench.common.tree.LittleTree.frt;
import static gbench.common.tree.LittleTree.kvp_int;

/**
 * NVec的简单矩阵变形操作
 * @author Administrator
 *
 */
public class JunitMx {
    
    /**
     * nvec数值向量转矩阵
     */
    @Test
    public void nvec2mx() {
        
        final var mx1 = NVec.of(rG(0,100))
            .slidingS(2, 2, NVec::new).filter(e->e.size()>=2)
            .collect(ssclc(compose_f(DataMatrix::simpleOf,Seq::toArrayR)));
        System.out.println("行序:\n"+mx1);
        
        final var mx2 = NVec.of(rG(0,100))
            .slidingS(2, 2, NVec::new).filter(e->e.size()>=2)
            .collect(ssclc(compose_f(DataMatrix::simpleOf,Seq::toArrayC)));
        System.out.println("列序:\n"+mx2);
    }
    
    /**
     * xvec高纬数组转矩阵
     */
    @Test
    public void xvec2mx() {
        
        final var size = 1000;
        final var matlib = new MatlibCanvas(size);
        
        System.out.println("\n--------DataMatrix-------------------------");
        final var ponits_0 = P2(-PI,PI,10).map(matlib.rhotheta_affine(1, 1, 250, 250));
        final var mx= Seq.matrix_rows(ponits_0);
        System.out.println(mx);
        System.out.println("_B 列:"+mx.cOl("_B",e->e));
        System.out.println("0 列:"+mx.coL(0, NVec::new));
        System.out.println("1 列:"+mx.coL(1, NVec::new));
        
        System.out.println("\n--------NVec.toArray2-------------------------");
        final var points_1 = P2(-PI,PI,10).map(matlib.rhotheta_affine_offset(250, 250));// 生成一组xy的点
        final var xvec = NVec.toArray2(points_1,compose_f(XVec::OF,Seq::transpose)).fmap(NVec::new);
        xvec.foreach((i,v)->{
            System.out.println(i+"-->"+v);
        });
        
        System.out.println("\n--------XVec.toArrayR-------------------------");
        final var points_2 = P2(-PI,PI,10).map(matlib.rhotheta_affine_offset(250, 250));
        final var rr = Seq.toArrayR(points_2,XVec::OF).fmap(NVec::new);
        rr.foreach((i,v)->{
            System.out.println(i+"-->"+v);
        });
        
        System.out.println("\n--------XVec.toArrayC-------------------------");
        final var points_3 = P2(-PI,PI,10).map(matlib.rhotheta_affine_offset(250, 250));
        final var cc = Seq.toArrayC(points_3,XVec::OF).fmap(NVec::new);
        cc.foreach((i,v)->{
            System.out.println(i+"-->"+v);
        });
    }
    
    /**
     * 向量reshape
     */
    @Test
    public void reshape() {
        
        final var n = 25; // 行数
        final var size = n*5; // 数据的长度需要确保是n的整数倍,应为接下来会对size金宠重排序,如何不是整数倍,reshape的时候由于采用循环补填会造成排序结果混乱。
        final var mx = NVec.of(Range.of(size)).map(LittleTree.kvp_int()).sorted((a, b) ->
            Stream.of(a, b).map(KVPair::key).map(e -> NVec.intdiv(e, n).i4(1)).reduce(Integer::compare).get() // 按照列进行排序
        ).map(KVPair::value).collect(aaclc(NVec::new)).reshape2mx(n, size/n);
        System.out.println("列序矩阵:\n"+mx);
    }
    
    /**
     * 协方差矩阵
     */
    @Test
    public void cov() {
        
        final var xx = rG(1, 100).map(e->ImageOps.rnddbl()).collect(aaclc(NVec::new));// 生成100个数字的随机序列
        System.out.println("原始数据向量:\n"+xx);
        final var cols = xx.reshape(aa -> XVec.OF((Double[][]) aa).fmap(NVec::new), 10, 10);// 生成一个列序矩阵
        System.out.println("\n列向量集合:");
        cols.foreach((i,col)->{System.out.println(i+"-->"+col);}); // 列集合
        
        final var dframe = A2REC(cols.fmap(e->e.toArray()).toArray()); // 转换成数据框格式
        System.out.println("\n数据框格式:\n"+dframe.toString2(frt(5)));
        
        System.out.println("\n行的统计和");
        System.out.println(cols.reduce2(NVec::add));
        System.out.println("\n列的统计和:");
        System.out.println(cols.fmap(e->e.sum()));
        
        // 协方差矩阵
        final var n = cols.size(); // 提取数据向量的维度
        final var covmx = Range.cph2(n,n) // 索引全排序
            .map(idx ->cols.iat(idx).reduce2(NVec::corN).car()
            ).collect(llclc(NVec::of)).reshape2mx(10, 10);// 转换成协方差矩阵
        System.out.println("\ncov 协方差矩阵:\n"+covmx.toString(LittleTree.frt(5)));
    }
    
    @Test
    public void mx_col_order() {
        final var size = 100; // 总数量
        final var n  = 10 ; // 列高度
        final var xvec = rg(0, size).stream(kvp_int(NVec.modeOf(n,1)))
            .sorted((a,b)->a._1().compareTo(b._1())) // 按照列序进行排序
            .map(e -> e._2()).collect(aaclc(NVec::new)); // 拼接成NVec
        System.out.println("列顺序矩阵：\n"+xvec.reshape2mx(n, size/10));
    }
    
    @Test
    public void mx_row_order() {
        final var size = 100; // 总数量
        final var n  = 10; // 行宽度
        final var xvec = rg(0, size).collect(aaclc(NVec::new)); // 拼接成NVec
        System.out.println("行顺序矩阵：\n"+xvec.reshape2mx(size/10, n));
    }
}
